package com.boarsoft.dao.sharding.gaussdb.hibernate.inspector;

import com.alibaba.druid.pool.DruidDataSource;
import com.boarsoft.dao.sharding.bean.JdbcUrlInfo;
import com.boarsoft.dao.sharding.bean.ShardingParam;
import com.boarsoft.dao.sharding.datasource.DynamicDataSource;
import com.boarsoft.dao.sharding.util.JdbcUrlUtil;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectBody;
import org.hibernate.resource.jdbc.spi.StatementInspector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

/**
 * 适配高斯数据库SQL路由
 *
 * @author chench
 * @desc com.boarsoft.dao.sharding.gaussdb.hibernate.inspector.HibernateInspector
 * @date 2024.01.19
 */
@Configuration
public class HibernateInspector implements StatementInspector {
    private static final Logger logger = LoggerFactory.getLogger(HibernateInspector.class);
    private static String HINT = "/*+db=%s_0100*/";

    private static String jdbcUrl;

    @Autowired(required = false)
    private DruidDataSource dataSource;

    @PostConstruct
    public void init() {
        if (dataSource == null) {
            return;
        }
        HibernateInspector.jdbcUrl = dataSource.getUrl();
    }

    @Override
    public String inspect(String sql) {
        ShardingParam sp = DynamicDataSource.getBinding();
        if (sp == null) {
            return sql;
        }
        String uid = (String) sp.getKey();
        try {
            if ("-1".equals(uid)) {
                String databaseName = calDatabaseName(sql);
                if (databaseName == null || "null".equals(databaseName) || "".equals(databaseName.trim())) {
                    JdbcUrlInfo jdbcUrlInfo = JdbcUrlUtil.parseJdbcUrl(jdbcUrl);
                    databaseName = jdbcUrlInfo.getDatabase();
                    if (databaseName == null || "null".equals(databaseName) || "".equals(databaseName.trim())) {
                        logger.warn("parse database name from jdbc url is empty, url: {}", jdbcUrl);
                    }
                }
                return new StringBuilder().append(String.format(HINT, databaseName))
                        .append(sql).toString();
            }
        } catch (JSQLParserException e) {
            logger.error("inspect err! sql: {}, ex: {}", sql, e.getMessage(), e);
        }
        return sql;
    }

    /**
     * 获取数据库名
     *
     * @param processSql
     * @return
     * @throws JSQLParserException
     */
    private String calDatabaseName(String processSql) throws JSQLParserException {
        // 构建解析器
        Select select = (Select) CCJSqlParserUtil.parse(processSql);
        // 获取select对象
        SelectBody selectBody = select.getSelectBody();
        // 解析sql
        PlainSelect plainSelect = (PlainSelect) selectBody;
        // 解析表对象
        Table table = (Table) plainSelect.getFromItem();
        // 返回数据库名称
        return table.getSchemaName();
    }
}